package vip.xiaonuo.modular.common;

import com.alibaba.fastjson.JSONArray;
import org.springframework.util.StringUtils;

import java.awt.geom.Point2D;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Author: liu
 * @Date:2022/9/21
 */
public class DistanceHelper {
    /**
     *
     * @Description 计算给定经纬度附近相应公里数的经纬度范围
     * @param longitude 经度
     * @param latitude 纬度
     * @param distance 距离（千米）
     * @return BigDecimal[] 格式：经度最小值-经度最大值-纬度最小值-纬度最大值
     * @Data 2018.10.26
     **/
    public static String[] getNearbyDistance(BigDecimal longitude, BigDecimal latitude, Integer distance) {
        double r = 6371.393; // 地球半径千米
        double lng = longitude.doubleValue();
        double lat = latitude.doubleValue();
        double dlng = 2 * Math.asin(Math.sin(distance / (2 * r)) / Math.cos(lat * Math.PI / 180));
        dlng = dlng * 180 / Math.PI;// 角度转为弧度
        double dlat = distance / r;
        dlat = dlat * 180 / Math.PI;
        double minlat = lat - dlat;
        double maxlat = lat + dlat;
        double minlng = lng - dlng;
        double maxlng = lng + dlng;
        String[] result = {new BigDecimal(minlng).setScale(6,3).toPlainString(),
                new BigDecimal(maxlng).setScale(6,3).toPlainString(),
                new BigDecimal(minlat).setScale(6,3).toPlainString(),
                new BigDecimal(maxlat).setScale(6,3).toPlainString()};
        return result;
//        return minlng + "-" + maxlng + "-" + minlat + "-" + maxlat;
    }

    /**
     * @Description 根据经纬度获取两点之间的距离
     * @param lng1 地点1经度
     * @param lat1 地点1纬度
     * @param lng2 地点2经度
     * @param lat2 地点2纬度
     * @return 距离：单位 米
     */
    public static Double getDistince(double lng1, double lat1, double lng2, double lat2) {
        double r = 6371.393; // 地球半径千米
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
                Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
        s = s * r;
        return s;
    }
    private static Double rad(double d) {
        return d * Math.PI / 180.0;
    }

    public static double parseDouble(String s){
        if (StringUtils.isEmpty(s)) {
            return 0;
        }
        if(s.length()>10){
            s = s.substring(0,10);
        }
        return Double.parseDouble(s);
    }

    public static String calcSampleSQL(Double scale,double start,double end) {
        if(scale <= start){
            return " sample 0.01 ";
        }else if(scale < end){
            String s = new BigDecimal((scale - start)/(end-start)).setScale(4, 4).toPlainString();
            return " sample "+s +" ";
        }else{
            return " sample 1 ";
        }
    }

    /**
     * 判断点是否在多边形内
     * @param point 检测点
     * @param pts   多边形的顶点
     * @return      点在多边形内返回true,否则返回false
     */
    public static boolean isPtInPoly(Point2D.Double point, List<String> points){
        List<Point2D.Double> pts = new ArrayList<>();
        for (String s : points) {
            String[] split = s.split(",");
            Point2D.Double d = new Point2D.Double(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
            pts.add(d);
        }
        int N = pts.size();
        boolean boundOrVertex = true; //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
        int intersectCount = 0;
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        Point2D.Double p1, p2;
        Point2D.Double p = point; //当前点
        p1 = pts.get(0);
        for(int i = 1; i <= N; ++i){
            if(p.equals(p1)){
                return boundOrVertex;
            }
            p2 = pts.get(i % N);
            if(p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)){
                p1 = p2;
                continue;
            }
            if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){
                if(p.y <= Math.max(p1.y, p2.y)){
                    if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){
                        return boundOrVertex;
                    }
                    if(p1.y == p2.y){
                        if(p1.y == p.y){
                            return boundOrVertex;
                        }else{
                            ++intersectCount;
                        }
                    }else{
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
                        if(Math.abs(p.y - xinters) < precision){
                            return boundOrVertex;
                        }
                        if(p.y < xinters){
                            ++intersectCount;
                        }
                    }
                }
            }else{
                if(p.x == p2.x && p.y <= p2.y){
                    Point2D.Double p3 = pts.get((i+1) % N);
                    if(p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)){
                        ++intersectCount;
                    }else{
                        intersectCount += 2;
                    }
                }
            }
            p1 = p2;
        }
        if(intersectCount % 2 == 0){
            return false;
        } else {
            return true;
        }
    }

    /**
     * 计算多边形的最最大矩形
     * 返回最小经度，最大经度，最小纬度，最多纬度
     * @param customPolygons
     * @return
     */
    public static Map<String,String> maxRectangle(List<String> customPolygons){
        double[] lngList = customPolygons.stream().mapToDouble(s -> Double.parseDouble(s.split(",")[0].trim())).toArray();
        double[] latList = customPolygons.stream().mapToDouble(s -> Double.parseDouble(s.split(",")[1].trim())).toArray();
        Map<String, String> map = new HashMap<>();
        map.put("lng1", String.valueOf(Arrays.stream(lngList).min().getAsDouble()));
        map.put("lng2", String.valueOf(Arrays.stream(lngList).max().getAsDouble()));
        map.put("lat1", String.valueOf(Arrays.stream(latList).min().getAsDouble()));
        map.put("lat2", String.valueOf(Arrays.stream(latList).max().getAsDouble()));
        return map;
    }

    /**
     * 获取网格左上角和右下角点位
     * lng1,lng2,lat1,lat2
     * @param polygon
     * @return
     */
    public static BigDecimal[] getPolygonArrayRange(JSONArray polygon){
        //取1，3号点
        if(polygon.size()<3){
            return null;
        }
        JSONArray p1 = (JSONArray)polygon.get(0);
        JSONArray p2 = (JSONArray)polygon.get(2);
        BigDecimal lng1 = p1.getBigDecimal(0);
        BigDecimal lat1 = p1.getBigDecimal(1);
        BigDecimal lng2 = p2.getBigDecimal(0);
        BigDecimal lat2 = p2.getBigDecimal(1);
        if (lng1.compareTo(lng2)>0) {
            BigDecimal t = lng1;
            lng1 = lng2;
            lng2 = t;
        }
        if (lat1.compareTo(lat2)>0) {
            BigDecimal t = lat1;
            lat1 = lat2;
            lat2 = t;
        }
        BigDecimal[] result = {lng1,lng2,lat1,lat2};
        return result;
    }
}
